home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / LSC_MACW / MWR_READ.C next >
Text File  |  1988-12-03  |  10KB  |  333 lines

  1. /*----------------------------------------------------------------------
  2.  MacWrite file to TEXT file converter.
  3.  Ignores pictures, does not treat tabs correctly.
  4.  But what the heck, it's a good start, and it's free.
  5.  Dan Kegel (d.r.kegel @ GEnie) November '88
  6. ------------------------------------------------------------------------*/
  7.  
  8. /* Get type definitions and prototypes for this module. */
  9. #include "mwr.h"
  10.  
  11. /* Prototypes for private functions. */
  12. static void  Lose(char *);
  13. static void *MyNewHandle(Size);
  14. static void  MySetHandleSize(Handle, Size);
  15.  
  16. /*--------------------------------------------------------------------
  17.  Report a fatal error to the user, then exit to the Finder (or whoever).
  18.  Calls FileError() in mini.file.c, which puts an alert on the screen
  19.  and waits for user to hit OK.
  20. ----------------------------------------------------------------------*/
  21. static void
  22. Lose(s)
  23.     char *s;
  24. {
  25.     FileError(s, "\p");
  26.     ExitToShell();
  27. }
  28.  
  29. /*---------------------------------------------------------------------
  30.  Routine to create a handle of given size; any errors are reported to
  31.  the user, then terminate the program.
  32.  Use when you don't expect any errors, but want to check just in case.
  33. -----------------------------------------------------------------------*/
  34. static void *
  35. MyNewHandle(n)
  36.     Size n;
  37. {
  38.     void *result;
  39.     
  40.     result = (void *) NewHandle(n);
  41.     if (result == (void *)0)
  42.         Lose("\pOut of memory!");
  43.     return result;
  44. }
  45.  
  46. /*---------------------------------------------------------------------
  47.  Routine to resize a handle to given size; any errors are reported to
  48.  the user, then terminate the program.
  49.  Use when you don't expect any errors, but want to check just in case.
  50. -----------------------------------------------------------------------*/
  51. static void
  52. MySetHandleSize(h, n)
  53.     Handle h;
  54.     Size n;
  55. {
  56.     SetHandleSize(h, n);
  57.     if (MemErr != 0)
  58.         Lose("\pOut of memory!");
  59. }
  60.  
  61. /*----------------------------------------------------------------------
  62.  Read the given paragraph from the MacWrite file.
  63.  On entry, hPara is a handle to the buffer to store the data in;
  64.  it will be resized if it is too small.
  65.  Returns OSErr, which will be noErr if the operation succeded.
  66. ------------------------------------------------------------------------*/
  67. OSErr
  68. mwr_ReadParagraph(file, para_num, hPara)
  69.     mwr_opened_t *file;
  70.     int para_num;
  71.     Handle hPara;
  72. {
  73.     long filePos;
  74.     long byteCount;
  75.     OSErr errno;
  76.  
  77.     /* Determine where to read from the file, and seek there. */
  78.     filePos = file->hParaInfo[0][para_num].file_pos;
  79.  
  80.     if (errno = SetFPos(file->refNum, fsFromStart, filePos))
  81.         return errno;
  82.  
  83.     /* Determine how many bytes to read, allocate space, and read them. */
  84.     byteCount = file->hParaInfo[0][para_num].nbytes;
  85.     if (GetHandleSize(hPara) < byteCount) {
  86.         MySetHandleSize(hPara, byteCount);
  87.     }
  88.  
  89.     if (errno = FSRead(file->refNum, &byteCount, *hPara))
  90.         return errno;
  91.  
  92.     return noErr;
  93. }
  94.  
  95. /*-----------------------------------------------------------------------
  96.  Copy a paragraph of MacWrite text into hTextBuf.
  97.  Decompresses only if compress_bit was set in this paragraph's info record.
  98.  hTextBuf is resized if it is not big enough to hold the paragraph.
  99.  CompressTab is a 15-byte array of the most common chars; in compressed
  100.  text, a nibble with a value of 0..14 is replaced by the corresponding
  101.  char from CompressTab; a nibble of 15 indicates that the following two
  102.  nibbles are a less-common character.
  103.  
  104.  Returns number of chars in unpacked text.
  105. ------------------------------------------------------------------------*/
  106. #define GETNIB(c, ip, nib) { \
  107.     c = *ip;            \
  108.     if (nib == 1) {        \
  109.         c &= 0x0f;        \
  110.         ip++;            \
  111.     } else                \
  112.         c >>= 4;        \
  113.     nib ^= 1;            \
  114.     }
  115.  
  116. int
  117. mwr_unpack(hPara_info_arr, para_num, hPara, hTextBuf,
  118.         compressTab)
  119.     mwr_para_info_t **hPara_info_arr;
  120.     int para_num;            /* which paragraph */
  121.     Handle hPara;
  122.     Handle hTextBuf;
  123.     char *compressTab;
  124. {
  125.     int nbytes;
  126.  
  127.     /* Determine size of block when unpacked, resize output buffer
  128.      * if not big enough. 
  129.      */
  130.     nbytes = **((short **)hPara);
  131.     if (GetHandleSize(hTextBuf) < nbytes) {
  132.         MySetHandleSize(hTextBuf, nbytes);
  133.     }
  134.  
  135.     if (hPara_info_arr[0][para_num].compress_bit == 0) {
  136.         /* Not compressed, just copy. */
  137.         BlockMove( *((char **)hPara) + 2,
  138.                    *((char **)hTextBuf),
  139.                    nbytes);
  140.     } else {
  141.         /* Compressed; decompress and copy. */
  142.         register char *op = *((char **)hTextBuf);
  143.         register unsigned char *ip = *((unsigned char **)hPara) + 2;
  144.         register int nibbleInChar = 0;
  145.         register int n = nbytes;
  146.         register unsigned char c;
  147.         
  148.         while (n > 0) {
  149.             /* Get next nibble. */
  150.             GETNIB(c, ip, nibbleInChar)
  151.  
  152.             if (c == 15) {
  153.                 char d;
  154.                 /* Not a frequent flier.  Next two nibbles are char. */
  155.                 GETNIB(d, ip, nibbleInChar)
  156.                 GETNIB(c, ip, nibbleInChar)
  157.                 c |= (d << 4);
  158.             } else {
  159.                 /* Frequent flier.  Grab char from compressTab. */
  160.                 c = compressTab[c];
  161.             }
  162.  
  163.             *op++ = c;
  164.             n--;
  165.         }
  166.     }
  167.     
  168.     return nbytes;
  169. }
  170.  
  171. /*---------------------------------------------------------------------
  172.  Open the given MacWrite file, read its header and paragraph info
  173.  array, places a structure describing it in *result.
  174.  
  175.  Returns errno, which will be noErr if successful;
  176.  returns 1 if file is not in MacWrite 4.5 format.
  177.  
  178.  WARNING: only works with Mac Plus and better ROM's, because
  179.  it calls OpenRFPerm().
  180. -----------------------------------------------------------------------*/
  181. OSErr
  182. mwr_OpenFile(filename, vRef, result )
  183.     char *filename;                /* file to read (pascal string) */
  184.     int vRef;                    /* file is on this volume */
  185.     mwr_opened_t *result;        /* where to put result */
  186. {
  187.     mwr_para_info_h hParaInfo;    /* describes paragraphs in file */
  188.     Handle hPackTab;        /* for MacWrite compression table */
  189.     int refNum;
  190.     OSErr errno;
  191.     long byteCount;
  192.     long filePos;
  193.     long temp;
  194.     int rsrcRefNum;
  195.  
  196.     (void) pStrCopy(filename, result->name);
  197.     (void) PtoCstr(result->name);
  198.  
  199.     /* Open file's resource fork, read file compression table.
  200.      * Use OpenRFPerm rather than OpenResFile so we can specify
  201.      * the directory the file is on!  Won't work on old Fat Macs, tough.
  202.      */
  203.     rsrcRefNum = OpenRFPerm(filename, vRef, fsRdPerm);
  204.     if ((rsrcRefNum == -1) ||
  205.        (hPackTab = GetResource(MWR_COMPRESS_RTYPE, MWR_COMPRESS_RID))==0) {
  206.         /* Some fool stripped the resource fork of the MacWrite file.
  207.          * Assume that the compression table is
  208.          * " etnroaisdlhcfp".  Don't know how reliable this is!
  209.          */
  210.         pStrCopy("\p etnroaisdlhcfp", result->compressTab);
  211.     } else {
  212.         /* Use the real compression table. */
  213.         pStrCopy(*hPackTab, result->compressTab);
  214.         /* Close resource file, discard loaded resources. */
  215.         CloseResFile(rsrcRefNum);
  216.     }
  217.     PtoCstr(result->compressTab);
  218.  
  219.     /* Open file, read MacWrite header */
  220.     if ((errno = FSOpen(filename, vRef, &refNum)) != noErr)
  221.         return errno;
  222.     byteCount = sizeof(mwr_filehdr_t);
  223.     errno = FSRead(refNum, &byteCount, &result->header);
  224.     if (errno != noErr)
  225.         return errno;
  226.     /* Make sure it's the right format. */
  227.     if (result->header.macwrite_version != 6) {
  228.         /* Gack!  Don't understand this format.  Punt. */
  229.         FSClose(refNum);
  230.         return 1;
  231.     }
  232.  
  233.     /* Read 'information array' for main document */
  234.     filePos = result->header.doc_win.info_pos;
  235.     byteCount = result->header.doc_win.info_len;
  236.     temp = result->header.doc_nparagraphs * sizeof(mwr_para_info_t);
  237.     if (byteCount != temp) {
  238.         /* File is inconsistant or not in MacWrite format */
  239.         FSClose(refNum);
  240.         return 1;
  241.     }
  242.     if (errno = SetFPos(refNum, fsFromStart, filePos))
  243.         return errno;
  244.     hParaInfo = MyNewHandle(byteCount);
  245.     errno = FSRead(refNum, &byteCount, *hParaInfo);
  246.     if (errno != noErr) {
  247.         DisposHandle(hParaInfo);
  248.         return errno;
  249.     }
  250.  
  251.     /* Pack it all into an ugly structure */
  252.     result->refNum = refNum;
  253.     result->hParaInfo = hParaInfo;
  254.  
  255.     return noErr;
  256. }
  257.  
  258. /*--------------------------------------------------------------------
  259.  Close a MacWrite file after you have finished reading it.
  260. ----------------------------------------------------------------------*/
  261. void
  262. mwr_CloseFile( file )
  263.     mwr_opened_t *file;
  264. {
  265.     OSErr errno;
  266.     
  267.     errno = FSClose(file->refNum);
  268.     /* If we allowed writing to a file, we'd check the error code... */
  269.     
  270.     DisposHandle(file->hParaInfo);
  271. }
  272.  
  273. /*---------------------------------------------------------------------
  274.  Read the given MacWrite file, place it in the given TextEdit buffer.
  275.  This is kinda risky, because TextEdit buffers can only handle 32K of
  276.  data.  
  277.  Returns noErr if successful, 1 if file was read but was too
  278.  big to entirely fit, or a file manager error code if there was one.
  279. -----------------------------------------------------------------------*/
  280. OSErr
  281. mwr_TEReadFile(filename, vRef, hText )
  282.     void *filename;        /* file to read (pascal string) */
  283.     int vRef;            /* file is on this volume or directory */
  284.     TEHandle hText;        /* where to put text */
  285. {
  286.     Handle hPara;        /* for incoming paragraphs of text */
  287.     Handle hTextBuf;    /* ditto, after decompression */
  288.     mwr_opened_t file;    /* describes open file */
  289.     int para, nPara;
  290.     int count;
  291.     OSErr errno;
  292.     
  293.     errno = mwr_OpenFile((char *)filename, vRef, &file);
  294.     if (errno != noErr)
  295.         return errno;
  296.  
  297.     /* Allocate paragraph buffer, clear TextEdit buffer */
  298.     hPara = MyNewHandle(2048);        /* start off with 2K buffer */
  299.     hTextBuf = MyNewHandle(2048);
  300.     TESetSelect(0, (**hText).teLength, hText);
  301.     TEDelete( hText );
  302.     
  303.     /* For each paragraph in file */
  304.     nPara = file.header.doc_nparagraphs;
  305.     for (para=0; para < nPara; para++) {
  306.         if (file.hParaInfo[0][para].height > 0) {
  307.             /* Read paragraph in MacWrite format */
  308.             errno = mwr_ReadParagraph(&file, para, hPara);
  309.             if (errno != noErr) break;
  310.     
  311.             /* Convert to TEXT format */
  312.             count = mwr_unpack(file.hParaInfo, para, 
  313.                 hPara, hTextBuf, file.compressTab);
  314.  
  315.             /* Insert into TextEdit record */
  316.             if ((long) count + (long) hText[0]->teLength < 32760)
  317.                 TEInsert( *hTextBuf, count, hText );
  318.             else {
  319.                 /* Too much text! */
  320.                 errno = 1;
  321.                 break;
  322.             }
  323.         }
  324.     }
  325.  
  326.     /* Deallocate buffers, close input file */
  327.     DisposHandle(hTextBuf);
  328.     DisposHandle(hPara);
  329.     mwr_CloseFile(&file);
  330.  
  331.     return errno;
  332. }
  333.